package com.ruibang.glass.produce.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.produce.constant.Constants;
import com.ruibang.glass.produce.constant.ProduceErrorCode;
import com.ruibang.glass.produce.domain.req.CombinationTrendChartReq;
import com.ruibang.glass.produce.domain.req.ExportMonitorDataReq;
import com.ruibang.glass.produce.domain.req.HistMonitorDataReq;
import com.ruibang.glass.produce.domain.resp.HistMonitorBase;
import com.ruibang.glass.produce.domain.resp.HistMonitorData;
import com.ruibang.glass.produce.domain.resp.MonitorRuleInfo;
import com.ruibang.glass.produce.entity.Device;
import com.ruibang.glass.produce.entity.MonitorData;
import com.ruibang.glass.produce.entity.MonitorPoint;
import com.ruibang.glass.produce.mapper.MonitorDataMapper;
import com.ruibang.glass.produce.service.DeviceService;
import com.ruibang.glass.produce.service.MonitorDataService;
import com.ruibang.glass.produce.service.MonitorPointService;
import com.ruibang.glass.produce.service.MonitorRuleService;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import com.teaming.cloud.framework2.common.model.ResultBody;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: songJinKang
 * @CreateTime: 2023-11-17  09:49
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service
public class MonitorDataServiceImpl extends ServiceImpl<MonitorDataMapper, MonitorData> implements MonitorDataService {

    @Autowired
    private MonitorRuleService monitorRuleService;

    @Autowired
    private MonitorPointService monitorPointService;

    @Autowired
    private DeviceService deviceService;


    @Override
    public ResultBody queryHistMonitorDataCurve(HistMonitorDataReq histMonitorDataReq) {
        if (histMonitorDataReq == null) {
            throw new ServiceException(ProduceErrorCode.PARAM_IS_EMPTY.getCode(), ProduceErrorCode.PARAM_IS_EMPTY.getMsg());
        }
        if (StringUtils.isBlank(histMonitorDataReq.getMonitorId()) && StringUtils.isBlank(histMonitorDataReq.getDeviceId())) {
            throw new ServiceException(ProduceErrorCode.QUERY_TARGET_IS_NULL.getCode(), ProduceErrorCode.QUERY_TARGET_IS_NULL.getMsg());
        }
        //时间为空默认查询7天数据
        if (histMonitorDataReq.getStartTime() == null || histMonitorDataReq.getEndTime() == null) {
            LocalDateTime now = LocalDateTime.now();
            histMonitorDataReq.setStartTime(now.minusDays(7));
            histMonitorDataReq.setEndTime(now);
        }
        //查询历史数据
        List<MonitorData> monitorData = baseMapper.queryHistMonitorData(histMonitorDataReq);

        if (CollectionUtils.isNotEmpty(monitorData)) {
            List<HistMonitorData> histMonitorDataList = new ArrayList<>();
            Map<String, List<MonitorData>> monitorDataMap = monitorData.stream().collect(Collectors.groupingBy(MonitorData::getMonitorId));

            //根据monitorId获取阀值
            monitorDataMap.forEach((k, v) -> {
                HistMonitorData histMonitorData = new HistMonitorData();
                histMonitorData.setMonitorId(k);

                List<HistMonitorBase> histMonitorBaseList = new ArrayList<>();
                for (MonitorData mData : v) {
                    HistMonitorBase histMonitorBase = new HistMonitorBase();
                    histMonitorBase.setCollectTime(mData.getCollectTime());
                    histMonitorBase.setValue(mData.getValue());
                    histMonitorBaseList.add(histMonitorBase);
                }
                histMonitorData.setHistMonitorBase(histMonitorBaseList);


                //设置最大、最小值
                double max = v.stream().map(MonitorData::getValue).max(Comparator.comparing(x -> x)).orElse(0.0);
                double min = v.stream().map(MonitorData::getValue).max(Comparator.comparing(x -> x)).orElse(0.0);
                histMonitorData.setMaxValue(max);
                histMonitorData.setMinValue(min);

                //规则
                List<MonitorRuleInfo> monitorRuleInfoList = monitorRuleService.getMonitorRuleInfoByMonitorId(k);
                List<Float> ruleValues = monitorRuleInfoList.stream().map(MonitorRuleInfo::getRuleValue).sorted().collect(Collectors.toList());
                histMonitorData.setRuleData(ruleValues);

                histMonitorDataList.add(histMonitorData);

            });

            return ResultBody.success(histMonitorDataList);
        }

        return ResultBody.success(Collections.emptyList());
    }

    @Override
    public Map<String, Object> combinationTrendChart(CombinationTrendChartReq combinationTrendChartReq) {
        List<MonitorPoint> monitorPoints = monitorPointService.queryMonitorPoints(combinationTrendChartReq.getDeviceId());
        if (CollectionUtils.isNotEmpty(monitorPoints)) {
            monitorPoints = monitorPoints.stream().filter(e -> StringUtils.isNotBlank(e.getMonitorType())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(monitorPoints)) {
                //获取采集数据
                HistMonitorDataReq histMonitorDataReq = new HistMonitorDataReq();
                histMonitorDataReq.setDeviceId(combinationTrendChartReq.getDeviceId());
                histMonitorDataReq.setEndTime(combinationTrendChartReq.getEndTime());
                histMonitorDataReq.setStartTime(combinationTrendChartReq.getStartTime());
                List<MonitorData> hisMonitorData = baseMapper.queryHistMonitorData(histMonitorDataReq);
                //数据分类
                if (CollectionUtils.isNotEmpty(hisMonitorData)) {
                    Map<String, List<MonitorData>> monitorDataMap = hisMonitorData.stream().collect(Collectors.groupingBy(MonitorData::getMonitorId));
                    Map<String, Object> dataMap = new LinkedHashMap<>(16);
                    //根据类型分类
                    Map<String, List<MonitorPoint>> monitorTypeMap = monitorPoints.stream().collect(Collectors.groupingBy(MonitorPoint::getMonitorType));
                    monitorTypeMap.forEach((k, v) -> {
                        if (CollectionUtils.isNotEmpty(v)) {
                            Map<String, Object> monitorMap = new LinkedHashMap<>(16);
                            List<Double> mmList = new ArrayList<>();
                            List<LocalDateTime> collectTime = null;
                            for (MonitorPoint monitorPoint : v) {
                                List<MonitorData> monitorDta = monitorDataMap.get(monitorPoint.getMonitorId());
                                if (CollectionUtils.isNotEmpty(monitorDta)) {
                                    //监测数据
                                    monitorMap.put(monitorPoint.getMonitorName(), monitorDta.stream().map(MonitorData::getValue).collect(Collectors.toList()));
                                    //最大值
                                    Double max = monitorDta.stream().map(MonitorData::getValue).max(Double::compareTo).get();
                                    mmList.add(max);
                                    //最小值
                                    Double min = monitorDta.stream().map(MonitorData::getValue).min(Double::compareTo).get();
                                    mmList.add(min);
                                }
                                if (collectTime == null) {
                                    collectTime = monitorDta.stream().map(MonitorData::getCollectTime).collect(Collectors.toList());
                                }
                            }
                            monitorMap.put("time", collectTime);
                            monitorMap.put("max", mmList.stream().max(Double::compareTo).get());
                            monitorMap.put("min", mmList.stream().min(Double::compareTo).get());
                            dataMap.put(k, monitorMap);

                        }
                    });
                    return dataMap;
                }
            }
        }
        return Collections.emptyMap();
    }

    @Override
    public List<Map<String, Object>> queryHistMonitorData(HistMonitorDataReq histMonitorData) {
        //默认查询一天
        if (histMonitorData.getStartTime() == null || histMonitorData.getEndTime() == null) {
            LocalDateTime endTime = LocalDateTime.now();
            histMonitorData.setEndTime(endTime);
            histMonitorData.setStartTime(endTime.minusDays(1));
        }
        List<Map<String, Object>> dataList = new LinkedList<>();
        List<MonitorData> monitorData = baseMapper.queryMonitorData(histMonitorData);
        LinkedHashMap<String, List<MonitorData>> monitorDataMap = monitorData.stream().collect(Collectors.groupingBy(e -> e.getCollectTime().format(Constants.DATE_TIME_FORMATTER), LinkedHashMap::new, Collectors.toList()));
        monitorDataMap.forEach((k, v) -> {
            Map<String, Object> data = new LinkedHashMap<>();
            data.put("collectTime", k);
            for (MonitorData monitorDatum : v) {
                data.put(monitorDatum.getMonitorId(), monitorDatum.getValue());
            }
            dataList.add(data);
        });
        return dataList;
    }

    /**
     * @Description: 历史数据导出
     * @version v1.0
     * @author songJinKang
     * @date 2023-11-29 16:28
     */
    @Override
    public void exportMonitorData(ExportMonitorDataReq exportMonitorDataReq, HttpServletResponse response) {
//        List<MonitorData> monitorDataList = processMonitorDataTime(exportMonitorDataReq);
        List<MonitorData> monitorDataList = baseMapper.exportMonitorData(exportMonitorDataReq);
        if (CollectionUtils.isNotEmpty(monitorDataList)) {
            //获取监测点信息
            List<MonitorPoint> monitorPointList = monitorPointService.getMonitorPointByDeviceId(exportMonitorDataReq.getDeviceIds());

            //获取设备信息
            List<Device> devices = deviceService.getDeviceByIds(exportMonitorDataReq.getDeviceIds());

            if (CollectionUtils.isNotEmpty(monitorPointList) && CollectionUtils.isNotEmpty(devices)) {
                //设备对应点位信息
                Map<String, List<MonitorPoint>> devicePointMap = monitorPointList.stream().collect(Collectors.groupingBy(MonitorPoint::getDeviceId));
                //设备id对应详情
                Map<String, Device> deviceMap = devices.stream().collect(Collectors.toMap(Device::getDeviceId, e -> e));
                //根据时间分组得到监测点数据
                Map<String, List<MonitorData>> timeMonitorDataMap = monitorDataList.stream().collect(Collectors.groupingBy(e -> e.getCollectTime().format(Constants.GROUP_DATE_TIME)));

                //创建工作簿
                Workbook workbook = new SXSSFWorkbook(-1);
                //创建头样式
                CellStyle headCellStyle = workbook.createCellStyle();
                headCellStyle.setAlignment(HorizontalAlignment.CENTER);// 设置单元格水平方向对其方式
                headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 设置单元格垂直方向对其方式
                Font hFont = workbook.createFont();
                hFont.setFontName("宋体");
                hFont.setFontHeightInPoints((short) 11);
                hFont.setBold(true);
                headCellStyle.setFont(hFont);

                //创建数据列样式
                CellStyle cellStyle = workbook.createCellStyle();
                cellStyle.setAlignment(HorizontalAlignment.CENTER);// 设置单元格水平方向对其方式
                cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 设置单元格垂直方向对其方式
                Font font = workbook.createFont();
                font.setFontName("宋体");
                font.setFontHeightInPoints((short) 9);
                cellStyle.setFont(font);


                devicePointMap.forEach((k, v) -> {
                    Device device = deviceMap.get(k);
                    if (device != null) {
                        //创建sheet
                        Sheet sheet = workbook.createSheet(device.getDeviceName());

                        if (CollectionUtils.isNotEmpty(v)) {
                            //设置列宽
                            for (int i = 0; i < v.size() + 1; i++) {
                                sheet.setColumnWidth(i, 25 * 256);
                            }

                            //创建表头
                            Row headRow = sheet.createRow(0);
                            headRow.setHeight((short) 400);
                            Cell cell = headRow.createCell(0);
                            cell.setCellStyle(headCellStyle);
                            cell.setCellValue("采集时间");
                            for (int i = 0; i < v.size(); i++) {
                                Cell headCell = headRow.createCell(i + 1);
                                headCell.setCellStyle(headCellStyle);
                                headCell.setCellValue(v.get(i).getMonitorName());
                            }


                            //获取点位实时数据
                            Set<String> keySet = timeMonitorDataMap.keySet();
                            keySet = keySet.stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new));
                            int rowCount = 0;
                            for (String key : keySet) {
                                //创建行
                                Row row = sheet.createRow(rowCount + 1);
                                row.setHeight((short) 400);
                                //set采集时间
                                Cell dataCell = row.createCell(0);
                                dataCell.setCellValue(key);
                                dataCell.setCellStyle(cellStyle);
                                //设置监测点值
                                for (int j = 0; j < v.size(); j++) {
                                    //当前点位
                                    MonitorPoint monitorPoint = v.get(j);
                                    //实时数据
                                    List<MonitorData> monitorData = timeMonitorDataMap.get(key);
                                    Map<String, Double> monitorValueMap = monitorData.stream().collect(Collectors.toMap(MonitorData::getMonitorId, MonitorData::getValue));
                                    //创建监测点数据列
                                    Cell monitorDataCell = row.createCell(j + 1);
                                    Double data = monitorValueMap.get(monitorPoint.getMonitorId());
                                    monitorDataCell.setCellValue(data != null ? data.toString() : "");
                                    monitorDataCell.setCellStyle(cellStyle);
                                }
                                rowCount++;
                            }
                        }
                    }
                });

                //返回excel
                try {
                    response.setContentType("application/vnd.ms-excel");
                    response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("历史数据.xlsx", "utf-8"));
                    ServletOutputStream outputStream = response.getOutputStream();
                    workbook.write(outputStream);
                } catch (IOException e) {
                    throw new ServiceException(ProduceErrorCode.MONITOR_DATA_EXPORT_FAIL.getCode(), ProduceErrorCode.MONITOR_DATA_EXPORT_FAIL.getMsg());
                }

            }
        }
    }


    /**
     * @Description: 处理实时数据间隔问题
     * @version v1.0
     * @author songJinKang
     * @date 2023-11-29 20:09
     */
    private List<MonitorData> processMonitorDataTime(ExportMonitorDataReq exportMonitorDataReq) {
        List<MonitorData> monitorDataList = baseMapper.exportMonitorData(exportMonitorDataReq);
        List<MonitorData> filters = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(monitorDataList)) {
            Map<String, List<MonitorData>> dataMap = monitorDataList.stream().collect(Collectors.groupingBy(e -> e.getCollectTime().format(Constants.GROUP_DATE_TIME)));

            LocalDateTime startTime = exportMonitorDataReq.getStartTime();
            LocalDateTime endTime = exportMonitorDataReq.getEndTime();

            List<MonitorData> firstData = dataMap.get(startTime.format(Constants.GROUP_DATE_TIME));
            if (CollectionUtils.isNotEmpty(firstData)) {
                filters.addAll(firstData);
            }

            while (startTime.compareTo(endTime) != 0 && startTime.compareTo(endTime) <= 0) {
                startTime = startTime.plusMinutes(exportMonitorDataReq.getInterval());
                String timeStr = startTime.format(Constants.GROUP_DATE_TIME);
                List<MonitorData> data = dataMap.get(startTime.format(Constants.GROUP_DATE_TIME));
                if (CollectionUtils.isNotEmpty(data)) {
                    log.error("timeStr     ->   {}", timeStr);
                    filters.addAll(data);
                }
            }
        }
        return filters;
    }


}
